﻿using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using SlimDX;
using SlimDX.D3DCompiler;
using SlimDX.DXGI;
using SlimDX.Direct2D;
using SlimDX.Direct3D11;
using SlimDX.DirectInput;
using SlimDX.DirectWrite;
using SlimDX.Windows;
using Buffer = System.Buffer;
using Device = SlimDX.Direct3D11.Device;
using Effect = SlimDX.Direct3D11.Effect;
using Resource = SlimDX.Direct3D11.Resource;
using Factory = SlimDX.DXGI.Factory;
using DWFactory = SlimDX.DirectWrite.Factory;
using DX10Device = SlimDX.Direct3D10_1.Device1;
using DXGIResource = SlimDX.DXGI.Resource;
using DX10Texture2D = SlimDX.Direct3D10.Texture2D;
using DX2DFactory = SlimDX.Direct2D.Factory;
using EffectFlags = SlimDX.D3DCompiler.EffectFlags;
using FactoryType = SlimDX.DirectWrite.FactoryType;
using FontStyle = SlimDX.DirectWrite.FontStyle;

namespace InsTron
{
    public enum GameLobbyState : int
    {
        ScreenMode,
        Music,
        Supersampling,
        Resolution,
        Player1Color,
        Player2Color,
        Save,
        Cancel
    }


    public class LobbyView : IRenderable
    {
        private Device device;
        private DeviceContext immediateContext;
        private Effect effect;
        private EffectTechnique lobbyTechnique;
        private InputLayout lobbyInputLayout;
        private SlimDX.Direct3D11.Buffer simpleLobbyBuffer;
        private Texture2D lobbyTexture;
        private static GameLobbyState actualLobbyState;

        private RenderForm renderForm;

        #region DXGI
        private static Factory1 factory1;
        private static Adapter1 adapter1;
        #endregion

        #region MainMenu
        private DX10Device device10_1;
        private Texture2D textureD3D11;
        private DX10Texture2D textureD3D10;
        private DXGIResource sharedResource;
        private KeyedMutex mutexD3D10;
        private KeyedMutex mutexD3D11;
        private DX2DFactory d2Factory;
        private DWFactory dwFactory;
        private TextFormat headerTextFormat;
        private TextFormat optionTextFormat;
        private RenderTarget dwRenderTarget;
        private SolidColorBrush brushSolidAqua;
        private SolidColorBrush brushSolidRed;
        private BlendState blendStateTransparent;
        private DataStream verticesText;
        private InputLayout inputLayoutText;
        private SlimDX.Direct3D11.Buffer vertexBufferText;
        #endregion 

        #region Text
        private readonly static string screenModeHeaderTxt = "Screen mode";
        private readonly static string musicHeaderTxt = "Music";
        private readonly static string supersamplingHeaderTxt = "Supersampling";
        private readonly static string resolutionHeaderTxt = "Resolution";
        private readonly static string player1ColorHeaderTxt = "First player bike color";
        private readonly static string player2ColorHeaderTxt = "Second player bike color";
        private readonly static string saveHeaderTxt = "Save";
        private readonly static string cancelHeaderTxt = "Cancel";

        private static string screenModeOptionTxt = "";
        private static string musicOptionTxt = "";
        private static string supersamplingOptionTxt = "";
        private static string resolutionOptionTxt = "";
        private static string player1ColorOptionTxt = "";
        private static string player2ColorOptionTxt = "";

        private static IList<string> screenModesList;
        private static IList<string> confirmationList;
        private static IList<string> resolutionList;
        private static Dictionary<string, Color> colorsListDictionary;
        private static IList<string> colorsList;

        #endregion

        public LobbyView(Device device, RenderForm renderForm)
        {
            this.device = device;
            immediateContext = device.ImmediateContext;

            // set actual gameState
            actualLobbyState = GameLobbyState.ScreenMode;

            // DirectX DXGI 1.1 factory
            factory1 = new Factory1();

            // The 1st graphics adapter
            adapter1 = factory1.GetAdapter1(0);

            this.renderForm = renderForm;
            renderForm.KeyDown -= KeyDownForRenderForm;
            renderForm.KeyDown += KeyDownForRenderForm;

            InitializeAll();
        }


        public void InitializeAll()
        {
            LoadSettings();
            LoadEffects();
            ConfigureInputLayouts();
            LoadModels();
            LoadTextures();

            PrepareMenu();
            CreateVertexTextData();
            CreateVertexTextLayoutAndBuffer();
        }


        public void DisposeAll()
        {
            renderForm.KeyDown -= KeyDownForRenderForm;
            lobbyTexture.Dispose();
            effect.Dispose();
            simpleLobbyBuffer.Dispose();
            lobbyInputLayout.Dispose();
            verticesText.Close();
            factory1.Dispose();
            adapter1.Dispose();
            device10_1.Dispose();
            textureD3D11.Dispose();
            textureD3D10.Dispose();
            sharedResource.Dispose();
            mutexD3D10.Dispose();
            mutexD3D11.Dispose();
            d2Factory.Dispose();
            dwFactory.Dispose();
            headerTextFormat.Dispose();
            optionTextFormat.Dispose();
            dwRenderTarget.Dispose();
            brushSolidAqua.Dispose();
            brushSolidRed.Dispose();
            blendStateTransparent.Dispose();
            verticesText.Dispose();
            inputLayoutText.Dispose();
            vertexBufferText.Dispose();
        }

        private void LoadSettings()
        {
            screenModesList = new List<string> { "FullScreen", "Windowed"};
            confirmationList = new List<string>{"On", "Off"};
            resolutionList = Settings.GetResolutionKeysList();

            colorsListDictionary = new Dictionary<string, Color>
                             {
                                 { Color.Red.Name, Color.Red }, 
                                 { Color.Black.Name,Color.Black },
                                 { Color.Blue.Name,Color.Blue },
                                 { Color.Yellow.Name,Color.Yellow },
                                 { Color.Green.Name,Color.Green }
                             };
            colorsList = new List<string> { Color.Red.Name, Color.Black.Name, Color.Blue.Name, Color.Yellow.Name, Color.Green.Name };

            screenModeOptionTxt = Settings.Fullscreen ? screenModesList[0] : screenModesList[1];
            musicOptionTxt = confirmationList[1];
            supersamplingOptionTxt = Settings.SupersamplingFactor == 2 ? confirmationList[0] : confirmationList[1];
            resolutionOptionTxt = Settings.CurrentResolutionKey;
            player1ColorOptionTxt = Settings.BikeParameters[0].Color.Name;
            player2ColorOptionTxt = Settings.BikeParameters[1].Color.Name;
        }

        private void LoadEffects()
        {
            //wczytanie efektow z plikow i pobranie niezbednych technik
            using (var bytecode = ShaderBytecode.CompileFromFile("shaders\\OptionsMenu.fx", "fx_5_0"))
            {
                effect = new Effect(device, bytecode);
            }
            lobbyTechnique = effect.GetTechniqueByName("LobbyMenu");
        }


        private void ConfigureInputLayouts()
        {
            var inputSignature = lobbyTechnique.GetPassByIndex(0).Description.Signature;
            lobbyInputLayout = new InputLayout(device, inputSignature, VertexDeclarations.InputElements_PosTex);
            inputSignature.Dispose();
        }

        private void LoadModels()
        {
            //wczytanie modeli z plikow
            var vertices = new DataStream(20 * 6, true, true);
            vertices.Write(new Vector3(1.0f, 1.0f, 1.0f));
            vertices.Write(new Vector2(1.0f, 0.0f));
            vertices.Write(new Vector3(1.0f, -1.0f, 1.0f));
            vertices.Write(new Vector2(1.0f, 1.0f));
            vertices.Write(new Vector3(-1.0f, -1.0f, 1.0f));
            vertices.Write(new Vector2(0.0f, 1.0f));
            vertices.Write(new Vector3(-1.0f, 1.0f, 1.0f));
            vertices.Write(new Vector2(0.0f, 0.0f));
            vertices.Write(new Vector3(1.0f, 1.0f, 1.0f));
            vertices.Write(new Vector2(1.0f, 0.0f));
            vertices.Write(new Vector3(-1.0f, -1.0f, 1.0f));
            vertices.Write(new Vector2(0.0f, 1.0f));
            vertices.Position = 0;

            simpleLobbyBuffer = new SlimDX.Direct3D11.Buffer(device, vertices, 20 * 6, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
        }


        private void LoadTextures()
        {
            // wczytanie tekstur z plikow
            lobbyTexture = Texture2D.FromFile(device, "assets\\textures\\lobby.jpg");
        }

        public static void KeyDownForRenderForm(object sender, KeyEventArgs e)
        {
            var actualState = (int)actualLobbyState;
            switch (e.KeyCode)
            {
                case Keys.Up:
                    actualLobbyState = actualState > 0 ? (GameLobbyState)(--actualState) : GameLobbyState.Cancel;
                    break;

                case Keys.Down:
                    actualLobbyState = actualState == (int)GameLobbyState.Cancel ? GameLobbyState.ScreenMode : (GameLobbyState)(++actualState);
                    break;

                case Keys.Left:
                    ChangeOption(Keys.Left);
                    break;

                case Keys.Right:
                    ChangeOption(Keys.Right);
                    break;

                case Keys.Enter:
                    if (actualState == (int)GameLobbyState.Save)
                    {
                        SaveSettings();
                        Program.ChangeGameState(EProgramState.Menu);
                    }
                    else if (actualState == (int)GameLobbyState.Cancel)
                    {
                        Program.ChangeGameState(EProgramState.Menu);
                    }
                    break;

                case Keys.Escape:
                    Program.ChangeGameState(EProgramState.Menu);
                    break;
            }
        }

        private static void SaveSettings()
        {
            Settings.CommitSettingsChange(screenModeOptionTxt == screenModesList[0], 
                resolutionOptionTxt, 
                supersamplingOptionTxt == confirmationList[0], 
                colorsListDictionary[player1ColorOptionTxt],
                colorsListDictionary[player2ColorOptionTxt],
                musicOptionTxt == confirmationList[0]);
        }

        private static void ChangeOption(Keys key)
        {
            switch (actualLobbyState)
            {
                 case GameLobbyState.ScreenMode:
                    ChangeText(ref screenModeOptionTxt, screenModesList, key);
                    break;

                 case GameLobbyState.Music:
                    ChangeText(ref musicOptionTxt, confirmationList, key);
                    break;

                 case GameLobbyState.Supersampling:
                    ChangeText(ref supersamplingOptionTxt, confirmationList, key);
                    break;

                 case GameLobbyState.Resolution:
                    ChangeText(ref resolutionOptionTxt, resolutionList, key);
                    break;

                 case GameLobbyState.Player1Color:
                    ChangeText(ref player1ColorOptionTxt, colorsList, key);
                    break;

                 case GameLobbyState.Player2Color:
                    ChangeText(ref player2ColorOptionTxt, colorsList, key);
                    break;
            }
        }

        private static void ChangeText(ref string text, IList<string> options, Keys key)
        {
            var index = options.IndexOf(text);

            text = key == Keys.Left ? (index > 0 ? options[--index] : options[options.Count - 1]) : index == (options.Count - 1) ? options[0] : options[++index];
        }

        #region MainMenuMethods
        public void InitializeDX10Device()
        {
            device10_1 = new SlimDX.Direct3D10_1.Device1(
                adapter1,
                SlimDX.Direct3D10.DriverType.Hardware,
                SlimDX.Direct3D10.DeviceCreationFlags.BgraSupport | SlimDX.Direct3D10.DeviceCreationFlags.Debug,
                SlimDX.Direct3D10_1.FeatureLevel.Level_10_0
            );
        }

        public void CreateDX11Texture2D()
        {
            textureD3D11 = new Texture2D(device, new Texture2DDescription
            {
                Width = renderForm.Width,
                Height = renderForm.Height,
                MipLevels = 1,
                ArraySize = 1,
                Format = Format.B8G8R8A8_UNorm,
                SampleDescription = new SampleDescription(1, 0),
                Usage = ResourceUsage.Default,
                BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.KeyedMutex
            });
        }

        public void ShareTexture()
        {
            sharedResource = new SlimDX.DXGI.Resource(textureD3D11);
            textureD3D10 = device10_1.OpenSharedResource<DX10Texture2D>(sharedResource.SharedHandle);
        }

        public void InitializeMutexes()
        {
            mutexD3D10 = new KeyedMutex(textureD3D10);
            mutexD3D11 = new KeyedMutex(textureD3D11);
        }

        public void InitializeFactories()
        {
            // Direct2D Factory
            d2Factory = new SlimDX.Direct2D.Factory(
                SlimDX.Direct2D.FactoryType.SingleThreaded,
                DebugLevel.Information
            );

            // Direct Write factory
            dwFactory = new SlimDX.DirectWrite.Factory(
                FactoryType.Isolated
            );
        }
        public void InitializeTextFormat()
        {
            // The textFormat we will use to draw text with
            headerTextFormat = new TextFormat(
                dwFactory,
                "TR2N",
                FontWeight.Bold,
                FontStyle.Normal,
                FontStretch.Condensed,
                40,
                "en-US"
            ) { TextAlignment = SlimDX.DirectWrite.TextAlignment.Center, ParagraphAlignment = ParagraphAlignment.Near };

            optionTextFormat = new TextFormat(
                dwFactory,
                "TR2N",
                FontWeight.Bold,
                FontStyle.Normal,
                FontStretch.Condensed,
                30,
                "en-US"
            ) { TextAlignment = SlimDX.DirectWrite.TextAlignment.Center, ParagraphAlignment = ParagraphAlignment.Near };
        }

        public void InitializeBrush()
        {
            // Query for a IDXGISurface.
            // DirectWrite and DirectX10 can interoperate thru DXGI.
            Surface surface = textureD3D10.AsSurface();
            var rtp = new RenderTargetProperties
            {
                MinimumFeatureLevel = SlimDX.Direct2D.FeatureLevel.Direct3D10,
                Type = RenderTargetType.Hardware,
                Usage = RenderTargetUsage.None,
                PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)
            };
            dwRenderTarget = RenderTarget.FromDXGI(d2Factory, surface, rtp);

            // Brush used to DrawText
            brushSolidAqua = new SolidColorBrush(dwRenderTarget, new Color4(255.0f, 0, 255.0f, 255.0f));
            brushSolidRed = new SolidColorBrush(dwRenderTarget, new Color4(255.0f, 0, 0));
            surface.Dispose();
        }

        public void InitializeBlendState()
        {
            // Think of the shared textureD3D10 as an overlay.
            // The overlay needs to show the text but let the underlying triangle (or whatever)
            // show thru, which is accomplished by blending.
            var bsd = new BlendStateDescription();
            bsd.RenderTargets[0].BlendEnable = true;
            bsd.RenderTargets[0].SourceBlend = BlendOption.SourceAlpha;
            bsd.RenderTargets[0].DestinationBlend = BlendOption.InverseSourceAlpha;
            bsd.RenderTargets[0].BlendOperation = BlendOperation.Add;
            bsd.RenderTargets[0].SourceBlendAlpha = BlendOption.One;
            bsd.RenderTargets[0].DestinationBlendAlpha = BlendOption.Zero;
            bsd.RenderTargets[0].BlendOperationAlpha = BlendOperation.Add;
            bsd.RenderTargets[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;
            blendStateTransparent = BlendState.FromDescription(device, bsd);
        }

        public void CreateVertexTextData()
        {
            verticesText = new DataStream(20 * 6, true, true);
            verticesText.Write(new Vector3(0.0f, 0.8f, 1.0f));
            verticesText.Write(new Vector2(1.0f, 0.0f));
            verticesText.Write(new Vector3(0.0f, -1.0f, 1.0f));
            verticesText.Write(new Vector2(1.0f, 1.0f));
            verticesText.Write(new Vector3(-1.0f, -1.0f, 1.0f));
            verticesText.Write(new Vector2(0.0f, 1.0f));
            verticesText.Write(new Vector3(-1.0f, 0.8f, 1.0f));
            verticesText.Write(new Vector2(0.0f, 0.0f));
            verticesText.Write(new Vector3(0.0f, 0.8f, 1.0f));
            verticesText.Write(new Vector2(1.0f, 0.0f));
            verticesText.Write(new Vector3(-1.0f, -1.0f, 1.0f));
            verticesText.Write(new Vector2(0.0f, 1.0f));
            verticesText.Position = 0;

            vertexBufferText = new SlimDX.Direct3D11.Buffer(device, verticesText, (int)verticesText.Length, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
        }

        public void CreateVertexTextLayoutAndBuffer()
        {
            var inputSignature = lobbyTechnique.GetPassByIndex(0).Description.Signature;
            inputLayoutText = new InputLayout(device, inputSignature, VertexDeclarations.InputElements_PosTex);
            inputSignature.Dispose();
        }

        /// <summary>
        /// configure the Input Assembler portion of the pipeline with the vertex data
        /// </summary>
        public void ConfigureInputAssemblerForText()
        {
            immediateContext.InputAssembler.InputLayout = inputLayoutText;
            immediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            immediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertexBufferText, 20, 0));
            immediateContext.OutputMerger.BlendState = blendStateTransparent;
        }

        #endregion

        public void PrepareMenu()
        {
            InitializeDX10Device();
            CreateDX11Texture2D();
            ShareTexture();
            InitializeMutexes();
            InitializeFactories();
            InitializeTextFormat();
            InitializeBrush();
            InitializeBlendState();
        }

        public void RenderScene()
        {
            using (var resource = new ShaderResourceView(device, lobbyTexture))
            {
                effect.GetVariableByName("xMenuTexture").AsResource().SetResource(resource);
            }

            immediateContext.InputAssembler.InputLayout = lobbyInputLayout;
            immediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            immediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(simpleLobbyBuffer, 20, 0));
            immediateContext.OutputMerger.BlendState = null;
            for (int i = 0; i < lobbyTechnique.Description.PassCount; i++)
            {
                lobbyTechnique.GetPassByIndex(i).Apply(immediateContext);
                immediateContext.Draw(6, 0);
            }

            // Draw Text on the shared Texture2D
            // Need to Acquire the shared texture for use with DirectX10
            mutexD3D10.Acquire(0, 100);
            DrawText();
            mutexD3D10.Release(0);

            // Draw the shared texture2D onto the screen
            // Need to Aquire the shared texture for use with DirectX11
            mutexD3D11.Acquire(0, 100);
            var srv = new ShaderResourceView(device, textureD3D11);
            effect.GetVariableByName("xMenuTexture").AsResource().SetResource(srv);
            ConfigureInputAssemblerForText();
            for (int i = 0; i < lobbyTechnique.Description.PassCount; i++)
            {
                lobbyTechnique.GetPassByIndex(i).Apply(immediateContext);
                immediateContext.Draw(6, 0);
            }
            srv.Dispose();
            mutexD3D11.Release(0);
        }

        private void DrawText()
        {
            dwRenderTarget.BeginDraw();
            dwRenderTarget.Clear(new Color4(0, 0, 0, 0));
            int actualTxtPosition = 0;
            dwRenderTarget.DrawText(screenModeHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) headerTextFormat.FontSize + 5;
            dwRenderTarget.DrawText(screenModeOptionTxt, optionTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.ScreenMode ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) optionTextFormat.FontSize + 25;
            dwRenderTarget.DrawText(musicHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) headerTextFormat.FontSize + 5;
            dwRenderTarget.DrawText(musicOptionTxt, optionTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Music ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) optionTextFormat.FontSize + 25;
            dwRenderTarget.DrawText(supersamplingHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) headerTextFormat.FontSize + 5;
            dwRenderTarget.DrawText(supersamplingOptionTxt, optionTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Supersampling ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) optionTextFormat.FontSize + 25;
            dwRenderTarget.DrawText(resolutionHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) headerTextFormat.FontSize + 5;
            dwRenderTarget.DrawText(resolutionOptionTxt, optionTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Resolution ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) optionTextFormat.FontSize + 25;
            dwRenderTarget.DrawText(player1ColorHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) headerTextFormat.FontSize + 5;
            dwRenderTarget.DrawText(player1ColorOptionTxt, optionTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Player1Color ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) optionTextFormat.FontSize + 25;
            dwRenderTarget.DrawText(player2ColorHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int) headerTextFormat.FontSize + 5;
            dwRenderTarget.DrawText(player2ColorOptionTxt, optionTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Player2Color ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int)optionTextFormat.FontSize + 35;
            dwRenderTarget.DrawText(saveHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Save ? brushSolidRed : brushSolidAqua);
            actualTxtPosition = actualTxtPosition + (int)optionTextFormat.FontSize + 25;
            dwRenderTarget.DrawText(cancelHeaderTxt, headerTextFormat,
                                    new System.Drawing.Rectangle(0, actualTxtPosition, renderForm.Width, renderForm.Height),
                                    actualLobbyState == GameLobbyState.Cancel ? brushSolidRed : brushSolidAqua);
            dwRenderTarget.EndDraw();
        }
    }
}
